package cn1shared.ui;

import com.codename1.ui.Button;
import com.codename1.ui.Command;
import com.codename1.ui.Container;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Painter;
import com.codename1.ui.TextArea;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.geom.Rectangle;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.table.TableLayout;
import com.codename1.ui.util.Resources;

import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;


public abstract class StandardForm extends Form {

	public static Resources theme;

	private boolean built = false;
	protected final Form parent;

	private Container topPanel;
	private TextArea statusArea;

	private Container menuPanel = FormUtils.newContainer();
	private Set<Command> menuSet = new LinkedHashSet<Command>();
	private Button menuToggle;

	private boolean isMenuHorizontal = true;

	public StandardForm(String title, Form parent) {
		super(title);
		this.parent = parent;
	}

	protected StandardForm(String title) {
		this(title, null);
	}

	/** To be overridden */
	protected abstract Container getPanel() throws IOException;

	private void buildUI()
	{
		if (built)
			return;
		try {
			addDefaultActions();

			TableLayout layout = new TableLayout(1, 1);
			layout.setGrowHorizontally(true);

			Container panel = getContentPane();
			panel.setUIID("_DefaultBg");
			FormUtils.noSpacing(panel);
			panel.setLayout(layout);

			topPanel = FormUtils.newContainer(new BorderLayout());
			FormUtils.noSpacing(topPanel);
			menuPanel.getStyle().setBgColor(0xFFFFFF);
			menuPanel.setScrollIncrement(1);
			menuPanel.setSmoothScrolling(true);
			menuPanel.setScrollVisible(false);

			Container middlePanel = FormUtils.newContainer(new BorderLayout());
			FormUtils.noSpacing(middlePanel);
			middlePanel.setScrollableX(false);
			middlePanel.setScrollableY(true);
			middlePanel.addComponent(BorderLayout.NORTH, topPanel);
			middlePanel.addComponent(BorderLayout.CENTER, getPanel());

			panel.addComponent(middlePanel);
			built = true;
		} catch(IOException e) {
			if (retryDialog())
				buildUI();
			else
				Display.getInstance().exitApplication();
		}
	}

	private void addDefaultActions() {
		if (parent != null) {
			final Command back = new Command(" Back") {
				@Override public void actionPerformed(ActionEvent evt) { goBack(); }
			};
			back.setIcon(theme.getImage("back.png"));
			setBackCommand(back);
		}
		final Command topCommand = new Command(" Top ") {
			@Override
			public void actionPerformed(ActionEvent evt) {
				StandardForm.this.scrollComponentToVisible(topPanel);
			}
		};
		addCommand(topCommand);
	}

	protected void goBack() {
		parent.showBack();
	}

	protected void addMenuOptions(Command[] cmds) {
		for (Command c : cmds)
			menuSet.add(c);
		buildMenu();
	}

	protected void addMenuOptions(List<Command> cmds) {
		for (Command c : cmds)
			menuSet.add(c);
		buildMenu();
	}

	protected void addMenuOption(Command cmd) {
		menuSet.add(cmd);
		buildMenu();
	}

	protected void removeMenuOption(Command cmd) {
		menuSet.remove(cmd);
		buildMenu();
	}

	protected void clearMenu() {
		topPanel.removeComponent(menuPanel);
		menuSet.clear();
	}

	private static final BoxLayout BOX_X = new BoxLayout(BoxLayout.X_AXIS);
	private static final BoxLayout BOX_Y = new BoxLayout(BoxLayout.Y_AXIS);

	private void updateMenuStyle() {
		if (isMenuHorizontal) {
			menuPanel.setScrollableX(true);
			menuPanel.setScrollableY(false);
			menuPanel.setLayout(BOX_X);
		} else {
			menuPanel.setScrollableX(false);
			menuPanel.setScrollableY(true);
			menuPanel.setLayout(BOX_Y);
		}
	}

	private static final Painter painter = new Painter() {
		@Override public void paint(Graphics g, Rectangle rect) {
			g.setColor(0xf4f4f4);
			g.fillRoundRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), 10, 10);
		}
	};

	private void buildMenu() {
		if (menuToggle == null) {
			final Image vmenu = theme.getImage("vmenu.png");
			final Image hmenu = theme.getImage("hmenu.png");
			menuToggle = FormUtils.newButton(vmenu).noDots().background(0xffffff);
			FormUtils.setPadding(menuToggle, 0, 0, 0, 0);
			menuToggle.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent evt) {
					isMenuHorizontal = !isMenuHorizontal;
					if (isMenuHorizontal)
						menuToggle.setIcon(vmenu);
					else
						menuToggle.setIcon(hmenu);
					buildMenu();
				}
			});
		} else
			menuToggle.getParent().removeComponent(menuToggle);

		updateMenuStyle();
		menuPanel.removeAll();
		menuPanel.addComponent(FormUtils.boxX(menuToggle));

		for (Command c : menuSet) {
			Button b = FormUtils.newButton(c).noDots();
			b.setUIID("MenuEntry");
			b.getStyle().setBgPainter(painter);
			FormUtils.setPadding(b, 2, 2, 2, 2);
			menuPanel.addComponent(b);
		}
		if (menuPanel.getParent() == null)
			topPanel.addComponent(BorderLayout.NORTH, menuPanel);
		topPanel.revalidate();
	}

	/** To be overridden */
	protected void beforeShow() {}

	public void show() {
		buildUI();
		beforeShow();
		super.show();
	}

	public void showBack() {
		buildUI();
		removeStatus();
		beforeShow();
		super.showBack();
	}

	public void setStatus(String status) {
		if (statusArea == null) {
			statusArea = FormUtils.newTextLabel().alignCenter().font("large").background(0xf5f6af);
			FormUtils.setPadding(statusArea, 2, 2, 2, 2);
			topPanel.addComponent(BorderLayout.SOUTH, statusArea);
		}
		statusArea.setText(status);
		revalidate();
	}

	public void removeStatus() {
		if (statusArea != null) {
			topPanel.removeComponent(statusArea);
			statusArea = null;
		}
	}

	public static boolean retryDialog() {
		return Dialog.show("Connection Failed", "Unable to connect to the server.", "Retry", "Quit");
	}

	protected void hideTitleArea() {
		// hack
		Container titleArea = getTitleArea();
		titleArea.removeAll();
		FormUtils.setHeight(titleArea, 0);
	}

	public static abstract class RemoteCommand extends Command {

		public RemoteCommand() {
			super("");
		}
		public RemoteCommand(String command) {
			super(command);
		}

		/** To be overridden */
		protected abstract void call(ActionEvent evt) throws IOException;

		@Override
		public void actionPerformed(ActionEvent evt) {
			try {
				call(evt);
			} catch(IOException e) {
				if (retryDialog())
					actionPerformed(evt);
				else
					Display.getInstance().exitApplication();
			}
		}
	}

	protected void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {}
	}
}
